<?PHP
/**
 * OpenStation
 *
 * @Application : Curl.class.php
 * @Encode : 65001 Unicode ( UTF-8 NO BOM )
 * @Description : Curl
 * @Author : HK <hkyyang@gmail.com>
 */

class Curl{

    public $cookie = NULL;

    private $handle = NULL;

    private $Referer = NULL;

    private $Timeout = 30;

    private $RetryNum = 5;

    private $RetryWait = 5;

    private $FailNum = 0;

	/**
	 * 构造方法，初始化
	 *
	 * @access public
	 * @param $
	 * @return void
	 */
    public function __construct() {
        if( ! extension_loaded( 'curl' ) ) {
            throw_exception( Cache :: lang( 'NOT_LOAD_EXTENSION' ) . ': Curl' );
        }
    }

	/**
	 * setTimeout 方法，设置超时时间
	 *
	 * @access public
	 * @param Integer : $sec
	 * @return void
	 */
    public function setTimeout( $sec ) {
        $this -> Timeout = intval( $sec );
    }

    public function setReferer( $referer ) {
        $this -> Referer = $referer;
    }

    public function setRetryNum( $RetryNum ) {
        $this -> RetryNum = $RetryNum;
    }

	/**
	 * httpGet 方法，发送GET请求
	 *
	 * @access public
	 * @param String : $url, URL地址
	 * @param Array : $data, 请求参数数组
	 * @param String : $cookie 保存在本地的Cookie文件路径
	 * @param String : $proxy 代理服务器(格式 ip:port)
	 * @return void
	 */
    public function httpGet( $url, $data = array(), $cookie = NULL, $porxy = NULL ) {
        return $this -> httpSend( $url, 'GET', $data, $cookie, $porxy );
    }

	/**
	 * httpPost 方法，发送POST请求
	 *
	 * @access public
	 * @param String : $url, URL地址
	 * @param Array : $data, 请求参数数组
	 * @param String : $cookie 保存在本地的Cookie文件路径
	 * @param String : $proxy 代理服务器(格式 ip:port)
	 * @return void
	 */
    public function httpPost( $url, $data = array(), $cookie = NULL, $porxy = NULL ) {
        return $this -> httpSend( $url, 'POST', $data, $cookie, $porxy );
    }

	/**
	 * httpSend 方法，发送一个http请求
	 *
	 * @access private
	 * @param String : $url, URL地址
	 * @param String : $method, 请求方法 GET | POST
	 * @param Array : $data, 请求参数数组
	 * @param String : $cookie 保存在本地的Cookie文件路径
	 * @param String : $proxy 代理服务器(格式 ip:port)
	 * @return *
	 */
    private function httpSend( $url, $method = 'GET', $data = array(), $cookie = NULL, $porxy = NULL, $Retry = FALSE ) {
        if( ! $Retry ) {
             $this -> FailNum = 0;
        }

        $url = string_prepend_replace( $url, 'http://' );
        $request = $this -> dataToRequest( $data );
        $this -> handle = curl_init();
        // Curl Options
        curl_setopt( $this -> handle, CURLOPT_URL, $url );
        if( $this -> Referer ) {
            curl_setopt( $this -> handle, CURLOPT_REFERER, $this -> Referer );
            $this -> setReferer( NULL );
        } else {
            curl_setopt( $this -> handle, CURLOPT_REFERER, $url );
        }
        curl_setopt( $this -> handle, CURLOPT_HEADER, FALSE );

        if( $this -> Timeout > 0 ) {
            curl_setopt( $this -> handle, CURLOPT_TIMEOUT, $this -> Timeout );
            $runtime_key = md5( $url . $method );
            runtime_count( $runtime_key );
        }

        if( IS_CLI ) {
            curl_setopt( $this -> handle, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1' );
        } else {
            curl_setopt( $this -> handle, CURLOPT_USERAGENT, $_SERVER[ 'HTTP_USER_AGENT' ] );
        }
        curl_setopt( $this -> handle, CURLOPT_HTTPHEADER, array(
            'Accept-Language: zh-cn,zh;q=0.5'
        ) );
        curl_setopt( $this -> handle, CURLOPT_ENCODING, 'gzip, deflate' );
        curl_setopt( $this -> handle, CURLOPT_AUTOREFERER, TRUE ); // 自动来路设置
        curl_setopt( $this -> handle, CURLOPT_FOLLOWLOCATION, 1 ); // 自动跳转
        curl_setopt( $this -> handle, CURLOPT_BINARYTRANSFER, TRUE );
        curl_setopt( $this -> handle, CURLOPT_RETURNTRANSFER, TRUE );

        // Porxy
        $this -> setCurlPorxy( $porxy );
        $this -> setCurlCookie( $cookie );
        // Method
        $this -> setCurlMethod( $url, $method, $request );
        $content = curl_exec( $this -> handle );
        curl_close( $this -> handle );
        // Line
        $Line = IS_CLI ? "\n" : '<br>';
        if( $this -> Timeout > 0 ) {
            // Timeout
            $timeend = runtime_count( $runtime_key, TRUE, 0 );
            if( $timeend >= $this -> Timeout ) {
                if( ++ $this -> FailNum >= $this -> RetryNum ) {
                    Log :: error( 'CURL :: Timeout( ' . $this -> Timeout . ') waiver!' );
                    echo 'TIMEOUT' . $Line;
                    return NULL;
                }
                Log :: error( 'CURL :: Timeout( ' . $this -> Timeout . ') Retry:' . $this -> FailNum . '/' . $this -> RetryNum . ', Wait ' . $this -> RetryWait );
                echo 'TIMEOUT : ' . $this -> FailNum . '/' . $this -> RetryNum . $Line;
                return self :: httpSend( $url, $method, $data, $cookie, $porxy, TRUE );
            }
        }
        // 空Cookie删除
        if( $this -> cookie && is_file( $this -> cookie ) && filesize( $this -> cookie ) < 1 ) {
            rm( $this -> cookie );
        }
        $this -> handle = NULL;
        return $content;
    }

	/**
	 * setCurlPorxy 方法，设置代理服务器
	 *
	 * @access private
	 * @param String : $porxy, 格式 ip:port
	 * @return void
	 */
    private function setCurlPorxy( $porxy ) {
        if( ! is_null( $porxy ) ) {
            if( ! strpos( $porxy, ':' ) ) {
                throw_exception( Cache :: lang( 'WRONG_PARAM' ) . ': setCurlPorxy :: $porxy = "' . $porxy . '"' );
            }
            $porxy = str_replace( "\s", '', $porxy );
            if( is_resource( $this -> handle ) ) {
                #curl_setopt( $this -> handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5 );
                curl_setopt( $this -> handle, CURLOPT_PROXY, $porxy );
            }
        }
    }

	/**
	 * setCurlCookie 方法，设置Cookie
	 *
	 * @access private
	 * @param String : $cookie, 文件地址
	 * @return void
	 */
    private function setCurlCookie( $cookie = NULL ) {
        if( is_resource( $this -> handle ) ) {
            if( ! is_null( $cookie ) ) {
                curl_setopt( $this -> handle, CURLOPT_COOKIEFILE, $cookie );
            // 没有传入Cookie
            } else {
                $this -> cookie = tempnam( '/tmp', 'cookie' );
                curl_setopt( $this -> handle, CURLOPT_COOKIEJAR, $this -> cookie ); //保存Cookie
                curl_setopt( $this -> handle, CURLOPT_COOKIEFILE, $this -> cookie ); //发送Cookie
            }
        }
    }

	/**
	 * setCurlMethod 方法，设置请求方法
	 *
	 * @access private
     * @param String : & $url
	 * @param String : $method
     * @param String : $data
	 * @return void
	 */
    private function setCurlMethod( & $url, $method = NULL, $data = NULL ) {
        $method = strtoupper( $method );
        if( ! in_array( $method, array( 'GET', 'POST' ) ) ) {
            throw_exception( Cache :: lang( 'METHOD_NOT_EXIST' ) . ': setCurlMethod :: "' . $method . '"' );
        }
        if( is_resource( $this -> handle ) ) {
            if( $method == 'POST' ) {
                curl_setopt( $this -> handle, CURLOPT_POST, 1 );
                curl_setopt( $this -> handle, CURLOPT_POSTFIELDS, $data );
            } else if( empty( $data ) ) {
                if( strpos( $url, '?' ) ) {
                    $url = string_append_replace( $url, '&' ) . $data;
                } else {
                    $url .= '?' . $data;
                }
            }
        }
    }

	/**
	 * dataToRequest 方法，把数据数组转换为请求字符串
	 *
	 * @access private
	 * @param $
	 * @return void
	 */
    private function dataToRequest( $data ) {
        $request = '';
		if( is_array( $data ) ) {
			foreach( $data as $k => $v ) {
				$request .= $k . '=' . $v . '&';
			}
            $request = string_after_remove( $request, '&' );
		}
		return $request;
    }

}
?>